"""
AST验证器

提供AST节点的验证功能，确保工作流的正确性。
"""

from typing import List, Dict, Any, Set
from abc import ABC, abstractmethod

from .base import Ast, AstNodeType, CompositeAst
from .nodes import *


class ValidationError(Exception):
    """验证错误"""
    pass


class ValidationRule(ABC):
    """验证规则抽象基类"""
    
    @abstractmethod
    def validate(self, ast: Ast) -> List[str]:
        """验证AST节点，返回错误信息列表"""
        pass


class NodeConfigValidationRule(ValidationRule):
    """节点配置验证规则"""
    
    def validate(self, ast: Ast) -> List[str]:
        """验证节点配置"""
        return ast.validate()


class CircularDependencyValidationRule(ValidationRule):
    """循环依赖验证规则"""
    
    def validate(self, ast: Ast) -> List[str]:
        """检查循环依赖"""
        errors = []
        visited = set()
        path = []
        
        if self._has_circular_dependency(ast, visited, path):
            errors.append(f"检测到循环依赖: {' -> '.join(path)}")
        
        return errors
    
    def _has_circular_dependency(self, ast: Ast, visited: Set[str], path: List[str]) -> bool:
        """递归检查循环依赖"""
        if ast.node_id in path:
            path.append(ast.node_id)
            return True
        
        if ast.node_id in visited:
            return False
        
        visited.add(ast.node_id)
        path.append(ast.node_id)
        
        # 检查子节点
        if hasattr(ast, 'children'):
            for child in ast.children:
                if self._has_circular_dependency(child, visited, path):
                    return True
        
        path.pop()
        return False


class DataFlowValidationRule(ValidationRule):
    """数据流验证规则"""
    
    def validate(self, ast: Ast) -> List[str]:
        """验证数据流的正确性"""
        errors = []
        
        # 收集所有节点的输入输出
        nodes = self._collect_all_nodes(ast)
        
        # 检查数据依赖
        for node in nodes:
            if hasattr(node, 'inputs'):
                for input_name, input_source in node.inputs.items():
                    if isinstance(input_source, str) and input_source.startswith('$'):
                        # 这是一个变量引用
                        var_name = input_source[1:]
                        if not self._is_variable_available(var_name, node, nodes):
                            errors.append(f"节点 {node.name} 引用了未定义的变量: {var_name}")
        
        return errors
    
    def _collect_all_nodes(self, ast: Ast) -> List[Ast]:
        """收集所有节点"""
        nodes = [ast]
        
        if hasattr(ast, 'children'):
            for child in ast.children:
                nodes.extend(self._collect_all_nodes(child))
        
        return nodes
    
    def _is_variable_available(self, var_name: str, current_node: Ast, all_nodes: List[Ast]) -> bool:
        """检查变量是否可用"""
        # 简化实现：假设所有变量都是全局可用的
        # 实际实现需要考虑作用域和执行顺序
        return True


class ResourceValidationRule(ValidationRule):
    """资源验证规则"""
    
    def validate(self, ast: Ast) -> List[str]:
        """验证资源使用"""
        errors = []
        
        # 检查文件路径
        if hasattr(ast, 'input_path') and ast.input_path:
            if not self._is_valid_path(ast.input_path):
                errors.append(f"无效的输入路径: {ast.input_path}")
        
        if hasattr(ast, 'output_path') and ast.output_path:
            if not self._is_valid_path(ast.output_path):
                errors.append(f"无效的输出路径: {ast.output_path}")
        
        # 检查并发限制
        if isinstance(ast, Parallel):
            if ast.max_workers <= 0:
                errors.append("并行节点的最大工作线程数必须大于0")
            elif ast.max_workers > 32:
                errors.append("并行节点的最大工作线程数不应超过32")
        
        return errors
    
    def _is_valid_path(self, path: str) -> bool:
        """检查路径是否有效"""
        # 简化实现：检查路径格式
        if not path or path.strip() == "":
            return False
        
        # 检查是否包含非法字符
        illegal_chars = ['<', '>', ':', '"', '|', '?', '*']
        for char in illegal_chars:
            if char in path:
                return False
        
        return True


class PerformanceValidationRule(ValidationRule):
    """性能验证规则"""
    
    def validate(self, ast: Ast) -> List[str]:
        """验证性能相关配置"""
        errors = []
        
        # 检查嵌套深度
        depth = self._calculate_depth(ast)
        if depth > 10:
            errors.append(f"工作流嵌套深度过深: {depth}，建议不超过10层")
        
        # 检查并行节点数量
        parallel_count = self._count_parallel_nodes(ast)
        if parallel_count > 5:
            errors.append(f"并行节点数量过多: {parallel_count}，可能影响性能")
        
        return errors
    
    def _calculate_depth(self, ast: Ast, current_depth: int = 0) -> int:
        """计算嵌套深度"""
        max_depth = current_depth
        
        if hasattr(ast, 'children'):
            for child in ast.children:
                child_depth = self._calculate_depth(child, current_depth + 1)
                max_depth = max(max_depth, child_depth)
        
        return max_depth
    
    def _count_parallel_nodes(self, ast: Ast) -> int:
        """统计并行节点数量"""
        count = 1 if isinstance(ast, Parallel) else 0
        
        if hasattr(ast, 'children'):
            for child in ast.children:
                count += self._count_parallel_nodes(child)
        
        return count


class AstValidator:
    """AST验证器"""
    
    def __init__(self):
        self.rules = [
            NodeConfigValidationRule(),
            CircularDependencyValidationRule(),
            DataFlowValidationRule(),
            ResourceValidationRule(),
            PerformanceValidationRule(),
        ]
    
    def validate(self, ast: Ast) -> List[str]:
        """验证AST"""
        all_errors = []
        
        for rule in self.rules:
            try:
                errors = rule.validate(ast)
                all_errors.extend(errors)
            except Exception as e:
                all_errors.append(f"验证规则 {rule.__class__.__name__} 执行失败: {e}")
        
        return all_errors
    
    def validate_strict(self, ast: Ast) -> None:
        """严格验证AST，有错误时抛出异常"""
        errors = self.validate(ast)
        if errors:
            error_msg = "\n".join(f"- {error}" for error in errors)
            raise ValidationError(f"AST验证失败:\n{error_msg}")
    
    def add_rule(self, rule: ValidationRule) -> None:
        """添加验证规则"""
        self.rules.append(rule)
    
    def remove_rule(self, rule_class: type) -> bool:
        """移除验证规则"""
        for i, rule in enumerate(self.rules):
            if isinstance(rule, rule_class):
                del self.rules[i]
                return True
        return False
    
    def validate_workflow(self, ast: Ast) -> Dict[str, Any]:
        """验证工作流并返回详细报告"""
        errors = self.validate(ast)
        
        # 收集统计信息
        stats = self._collect_statistics(ast)
        
        return {
            "valid": len(errors) == 0,
            "errors": errors,
            "statistics": stats,
            "recommendations": self._generate_recommendations(ast, errors)
        }
    
    def _collect_statistics(self, ast: Ast) -> Dict[str, Any]:
        """收集统计信息"""
        nodes = self._collect_all_nodes(ast)
        
        node_types = {}
        for node in nodes:
            node_type = node.node_type.value
            node_types[node_type] = node_types.get(node_type, 0) + 1
        
        return {
            "total_nodes": len(nodes),
            "node_types": node_types,
            "max_depth": self._calculate_depth(ast),
            "parallel_nodes": sum(1 for node in nodes if isinstance(node, Parallel))
        }
    
    def _collect_all_nodes(self, ast: Ast) -> List[Ast]:
        """收集所有节点"""
        nodes = [ast]
        
        if hasattr(ast, 'children'):
            for child in ast.children:
                nodes.extend(self._collect_all_nodes(child))
        
        return nodes
    
    def _calculate_depth(self, ast: Ast, current_depth: int = 0) -> int:
        """计算嵌套深度"""
        max_depth = current_depth
        
        if hasattr(ast, 'children'):
            for child in ast.children:
                child_depth = self._calculate_depth(child, current_depth + 1)
                max_depth = max(max_depth, child_depth)
        
        return max_depth
    
    def _generate_recommendations(self, ast: Ast, errors: List[str]) -> List[str]:
        """生成优化建议"""
        recommendations = []
        
        # 基于错误生成建议
        if any("循环依赖" in error for error in errors):
            recommendations.append("重新设计工作流结构，避免循环依赖")
        
        if any("嵌套深度过深" in error for error in errors):
            recommendations.append("考虑将复杂的工作流拆分为多个子工作流")
        
        if any("并行节点数量过多" in error for error in errors):
            recommendations.append("减少并行节点数量，或者调整并发配置")
        
        # 基于统计信息生成建议
        stats = self._collect_statistics(ast)
        if stats["total_nodes"] > 50:
            recommendations.append("工作流节点数量较多，考虑模块化设计")
        
        return recommendations


# 全局验证器实例
validator = AstValidator()
